#! /usr/bin/env node

const {program} = require('commander');
const inquirerObj = require('inquirer')
const path = require('path')
const ora = require('ora')
const clone = require('git-clone');
const fs = require('fs-extra')
const ejs = require('ejs')
const { green, yellow} = require('picocolors') // 同样的功能还有 chalk
const inquirer = inquirerObj.default
const pretty = require('pretty');
const htmlConfig = require('./html-config.cjs')

import { type IHtmlConfig, type HtmlConfigKey } from './data'
import dataConfig from './data-config'
import { getReg, formatTemplate, replaceTpl, duplicateRemove } from './utils'

const packageJson = require(path.join(__dirname, '../package.json'))

// 仓库地址
const repos: any = {
    // 'React-TypeScript': 'https://github.com/liz-q/react-ts-template.git',
    'React-TypeScript': 'git@coding.jd.com:mall_fe/project-template.git',
    'React-JavaScript': '',
    'Vue-TypeScript': '',
    'Vue-JavaScript': '',
}
program
    .name('create-jd-web')
    .description(green('京东 WEB 前端项目脚手架'))
    .version(packageJson.version)
    .option('--update', '更新 html 文件')

program.parse();

const options = program.opts();

/**
 * @description 修改 package.json
 * @param newProjectPath 项目目录
 * @param name name字段
 * */
function setPackageJson(newProjectPath: string, name: string) {
    try {
        let packageJson = fs.readFileSync(path.join(newProjectPath, './package.json'))
        packageJson = packageJson.toString()
        packageJson = JSON.parse(packageJson)
        packageJson.name = name
        packageJson.scripts['update-html'] = 'create-jdweb --update'
        fs.writeFileSync(path.join(newProjectPath, './package.json'), JSON.stringify(packageJson, null, 2))
    } catch (e) {
        console.log('\n ✖ 修改 package.json 文件时出错！')
        fs.removeSync(newProjectPath)
        process.exit(0)
    }
}

/**
 * @description 动态配置html
 * @param projectPath    工程目录
 * @param htmlTpl        html模板字符串
 * @param htmlConfigData html配置数据
 * @param errorDeleteDir 出错时是否删除工程
 * */
function setHtml(projectPath: string, htmlTpl: string, htmlConfigData: IHtmlConfig, errorDeleteDir: boolean) {
    try {
        // 新配置数据
        const configData: any = {}

        // 从 html-config 中将 true 的脚本增加，false 的脚本删除
        for (const key in htmlConfigData) {
            const configVal = htmlConfigData[key as HtmlConfigKey]
            const js_key = `${key}Js`
            const css_key = `${key}Css`

            if (Object.is(configVal, true)) {
                // 替换 js + css
                if (key === 'mallCommonComponent') {
                    configData[js_key] = formatTemplate(dataConfig[js_key], js_key)
                    configData[css_key] = formatTemplate(dataConfig[css_key], css_key)
                } else {
                    // 只替换 js
                    configData[key] = formatTemplate(dataConfig[key], key)
                }
            } else if (Object.is(configVal, false)) {
                if (key === 'mallCommonComponent') {
                    configData[js_key] = ''
                    configData[css_key] = ''
                } else {
                    configData[key] = ''
                }
            } else {
                // 带参数的
                // 烛龙监控
                if (key === 'dra') {
                    configData[key] = ejs.render(formatTemplate(dataConfig[key], key), configVal)
                } else {
                    configData[key] = ''
                }}
        }

        // 替换ejs模板
        htmlTpl = ejs.render(htmlTpl, configData)

        fs.writeFileSync(path.join(projectPath, './index.html'), pretty(htmlTpl, {
            ocd: true
        }))
    } catch (err) {
        console.log('设置html时出错', err)
        errorDeleteDir && fs.removeSync(projectPath)
        process.exit(0)
    }
}

/**
 * 更新html
 * */
async function updateHtml () {
    try {
        // todo 测试逻辑
        // fs.copySync(path.join(process.cwd(), './bb/html-config.js'), path.join(process.cwd(), './html-config.js'))
        // const htmlConfig = require(path.join(process.cwd(), './html-config.js'))
        // // 读取html字符串
        // const htmlStr = fs.readFileSync(path.join(process.cwd(), './bb/index.html'), 'utf-8')
        // // 将html转换成模板
        // const htmlTpl1 = replaceTpl(htmlStr, 'script')
        // const htmlTpl2 = replaceTpl(htmlTpl1, 'link')
        // // 去重
        // let htmlTpl3 = htmlTpl2
        // for (const key in dataConfig) {
        //     htmlTpl3 = duplicateRemove(htmlTpl3, `<%- ${key} %>`)
        // }
        // setHtml(path.join(process.cwd(), './bb'), htmlTpl3, htmlConfig, false)
        // fs.removeSync(path.join(process.cwd(), './html-config.js'))


        const htmlConfig = require(path.join(process.cwd(), './html-config.cjs'))
        // 读取html字符串
        const htmlStr = fs.readFileSync(path.join(process.cwd(), './index.html'), 'utf-8')
        // 将html转换成模板
        const htmlTpl1 = replaceTpl(htmlStr, 'script')
        const htmlTpl2 = replaceTpl(htmlTpl1, 'link')
        // 去重
        let htmlTpl3 = htmlTpl2
        for (const key in dataConfig) {
            htmlTpl3 = duplicateRemove(htmlTpl3, `<%- ${key} %>`)
        }
        setHtml(process.cwd(), htmlTpl3, htmlConfig, false)

        console.log(green('更新成功'))
    } catch (err) {
        console.log('更新html时出错', err)
        process.exit(0)
    }
}

/**
 * 创建新项目
 * */
async function createProject() {
    try {
        if (options.update) {
            updateHtml()
            return
        }

        // 创建新项目
        const answers: any = await inquirer.prompt([
            {
                type: 'input',
                name: 'projectName',
                message: 'Project name：',
                validate(value: string) {
                    if (value) {
                        const targetPath = path.join(process.cwd(), value)
                        if (fs.pathExistsSync(targetPath)) {
                            return yellow(`Target directory "${value}" is not empty，please input again.`)
                        }
                        return true
                    }
                    return false
                }
            },
            {
                type: 'list',
                name: 'framework',
                message: 'Select a framework',
                choices: [
                    'React',
                    {
                        name: 'Vue',
                        disabled: 'Unavailable at this time',
                    },
                ]
            },
            {
                type: 'list',
                name: 'variant',
                message: 'Select a variant',
                choices: [
                    "TypeScript",
                    {
                        name: 'JavaScript',
                        disabled: 'Unavailable at this time',
                    },
                ]
            }
        ])

        const repoType = `${answers.framework}-${answers.variant}`
        const newProjectPath = path.join(process.cwd(), answers.projectName)

        if (repos[repoType]) {
            const spinner = ora('Cloning repository...').start();
            clone(repos[repoType], newProjectPath, {
                // checkout: 'main'
                checkout: 'master'
            }, (err: any) => {
                if (!err) {
                    spinner.succeed('Repository cloned!');
                    // 拉取成功后删除 .git 文件夹
                    fs.removeSync(path.join(newProjectPath, './.git'))
                    // 修改package.json
                    setPackageJson(newProjectPath, answers.projectName)
                    // 动态配置html
                    setHtml(
                        newProjectPath,
                        fs.readFileSync(path.join(__dirname, './template.html'), 'utf-8'),
                        htmlConfig,
                        true
                    )
                    fs.copySync(path.join(__dirname, './html-config.cjs'), path.join(newProjectPath, './html-config.cjs'))

                    console.log('\n Done. Now run: \n')
                    console.log(`   cd ${answers.projectName}`)
                    console.log('   npm install')
                    console.log('   npm run dev')
                } else {
                    spinner.fail(`Clone failed: ${err.message}`);
                }
            });
        }

    } catch (err) {
        console.log('\n ✖ Operation cancelled')
        process.exit(0)
    }
}

program.parse();

createProject().catch((e) => {
    console.error(e)
    process.exit(1)
})